﻿using System;
using GeoAPI.Geometries;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Index.Strtree
{
	internal class BoundablePair<TItem> : IComparable<BoundablePair<TItem>>
	{
		public BoundablePair(IBoundable<Envelope, TItem> boundable1, IBoundable<Envelope, TItem> boundable2, IItemDistance<Envelope, TItem> itemDistance)
		{
			this._boundable1 = boundable1;
			this._boundable2 = boundable2;
			this._itemDistance = itemDistance;
			this._distance = this.GetDistance();
		}

		public IBoundable<Envelope, TItem> GetBoundable(int i)
		{
			if (i != 0)
			{
				return this._boundable2;
			}
			return this._boundable1;
		}

		private double GetDistance()
		{
			if (this.IsLeaves)
			{
				return this._itemDistance.Distance(this._boundable1, this._boundable2);
			}
			return this._boundable1.Bounds.Distance(this._boundable2.Bounds);
		}

		public double Distance
		{
			get
			{
				return this._distance;
			}
		}

		public int CompareTo(BoundablePair<TItem> o)
		{
			if (this._distance < o._distance)
			{
				return -1;
			}
			if (this._distance > o._distance)
			{
				return 1;
			}
			return 0;
		}

		public bool IsLeaves
		{
			get
			{
				return !BoundablePair<TItem>.IsComposite(this._boundable1) && !BoundablePair<TItem>.IsComposite(this._boundable2);
			}
		}

		public static bool IsComposite(IBoundable<Envelope, TItem> item)
		{
			return item is AbstractNode<Envelope, TItem>;
		}

		public void ExpandToQueue(PriorityQueue<BoundablePair<TItem>> priQ, double minDistance)
		{
			bool flag = BoundablePair<TItem>.IsComposite(this._boundable1);
			bool flag2 = BoundablePair<TItem>.IsComposite(this._boundable2);
			if (flag && flag2)
			{
				if (this._boundable1.Bounds.Area > this._boundable2.Bounds.Area)
				{
					this.Expand(this._boundable1, this._boundable2, priQ, minDistance);
					return;
				}
				this.Expand(this._boundable2, this._boundable1, priQ, minDistance);
				return;
			}
			else
			{
				if (flag)
				{
					this.Expand(this._boundable1, this._boundable2, priQ, minDistance);
					return;
				}
				if (flag2)
				{
					this.Expand(this._boundable2, this._boundable1, priQ, minDistance);
					return;
				}
				throw new ArgumentException("neither boundable is composite");
			}
		}

		private void Expand(IBoundable<Envelope, TItem> bndComposite, IBoundable<Envelope, TItem> bndOther, PriorityQueue<BoundablePair<TItem>> priQ, double minDistance)
		{
			foreach (IBoundable<Envelope, TItem> boundable in ((AbstractNode<Envelope, TItem>)bndComposite).ChildBoundables)
			{
				BoundablePair<TItem> boundablePair = new BoundablePair<TItem>(boundable, bndOther, this._itemDistance);
				if (boundablePair.Distance < minDistance)
				{
					priQ.Add(boundablePair);
				}
			}
		}

		private readonly IBoundable<Envelope, TItem> _boundable1;

		private readonly IBoundable<Envelope, TItem> _boundable2;

		private readonly double _distance;

		private readonly IItemDistance<Envelope, TItem> _itemDistance;
	}
}
